/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package edu.isi.pegasus.planner.subworkflow.scheduler.implementation;

import edu.isi.pegasus.planner.classes.ADag;
import edu.isi.pegasus.planner.classes.PegasusBag;
import edu.isi.pegasus.planner.subworkflow.partitioner.DAXAbstraction;
import edu.isi.pegasus.planner.subworkflow.partitioner.SiteAbstraction;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;

/**
 *
 * @author wchen
 */
public class MinMin extends ListScheduler{
    public MinMin(ADag dag, PegasusBag bag)
    {
        super(dag,bag);
        runQ = new LinkedList<DAXAbstraction>();
        doneQ = new LinkedList<DAXAbstraction>();
//        getChildrenMap = new HashMap<String, ArrayList>();
//        getParentsMap   = new HashMap<String, ArrayList>();
        //avail = new HashMap<SiteAbstraction, Double>();
//        weight = new HashMap<DAXAbstraction, Map>();
        ECT = new HashMap<String, Double>();
        FAT = new HashMap<String, Double>();
//        mSiteList = new HashMap<SiteAbstraction, ArrayList>();
    }
   
    private LinkedList runQ;
    private LinkedList doneQ;
    //private Map avail;
    private Map ECT;
    private Map FAT;

    private Map mSiteFile;

    @Override
    public void schedule()
    {
        //DAXAbstraction headNode = getHeadNode();
        //Fake();
        getHeadNode();
        runQ.add(headNode);
        while(!runQ.isEmpty())
        {
            double minTime = 1e10;
            int jobIndex = -1;
            int siteIndex = -1;

            for(int i = 0; i < runQ.size(); i ++)
            {
                DAXAbstraction bigDax = (DAXAbstraction)runQ.get(i);
                
                for(int j = 0; j < mSiteIndex.size(); j ++)
                {
                    SiteAbstraction site = (SiteAbstraction)mSiteIndex.get(j);

                    if(!FAT.containsKey(bigDax.adag.getName()))
                    {
                        FAT.put(bigDax.adag.getName(), 0.0);
                        System.out.println("Warning: bigDax's FAT is not set");
                    }
                    double runtime = (Double)FAT.get(bigDax.adag.getName());
                    double runtime1 = getavail(site);
                    runtime = (runtime > runtime1)? runtime:runtime1;
                    /*Warning*/
                    runtime = getweight(bigDax, site) + runtime + 50.0 + getSitePureSize(bigDax)/5e6;

                    if(runtime >= 1e10)System.err.println("runtime is too large");
                    if(runtime <= minTime)
                    {
                        //check space there should be something really complex instead of bigDax.size
                        double requiredSpace = getSiteSize(site, bigDax);
                        if(site.space >= requiredSpace *0.95)
                        //if(site.space >= bigDax.size * 0.95)
                        {
                            minTime = runtime;
                            jobIndex = i;
                            siteIndex = j;
                        }
                    }

                }
            }
            DAXAbstraction bigDax = (DAXAbstraction)runQ.get(jobIndex);

            SiteAbstraction site = (SiteAbstraction)mSiteIndex.get(siteIndex);
            double tmp = getweight(bigDax,site) + 50.0+getSitePureSize(bigDax)/10e6;
            System.out.println("Estimated Runtime: " + tmp +" for dax " + bigDax.adag.getName() );
            runQ.remove(bigDax);
            doneQ.add(bigDax);
            setSiteList(site, bigDax);

            ECT.put(bigDax.adag.getName(), minTime);
            if(bigDax.equals(headNode)||bigDax.equals(rearNode))
            {
                
            }
            else
            {
                /*Warning*/
                //site.space -= bigDax.size;
                //avail.put(site, minTime);
                setavail(site, minTime);
                String filename = bigDax.adag.getName() + ".xml";
                String mName = bigDax.adag.getName();
                addDAXJob2DAG(filename, mName , site.name);
                System.out.println("dax " + mName + " with size " + bigDax.size + " with degree " + bigDax.degree +
                " is mapped to " + site.name + " with slot " + site.slot);
            }



            //check
            ArrayList clist = (ArrayList)getChildrenMap.get(bigDax.adag.getName());
            if(clist == null)continue;
            for(int i = 0; i < clist.size(); i ++)
            {
                double runtime = 0.0;
                DAXAbstraction cDax = (DAXAbstraction)mDAXID2DAX.get((String)clist.get(i));
                ArrayList plist = (ArrayList)getParentsMap.get(cDax.adag.getName());
                boolean allHasScheduled = true;
                for(int j = 0; j < plist.size(); j++)
                {
                    DAXAbstraction pDax = (DAXAbstraction)mDAXID2DAX.get((String)plist.get(j));
                    if(!ECT.containsKey(pDax.adag.getName()))
                    {
                        //actually don't worry
                    }
                    else
                    {
                        double runtime1 = (Double)ECT.get(pDax.adag.getName());
                        //double runtime2 = (Double)weight.get(pDax) + runtime1;
                        if(runtime1 > runtime)runtime = runtime1;
                    }
                    if(!doneQ.contains(pDax))
                        allHasScheduled = false;
                }
                if(allHasScheduled && !runQ.contains(cDax))
                {
                    runQ.add(cDax);
                    FAT.put(cDax.adag.getName(), runtime);
                }
            }
        }
        

    }


}
